# -*- coding: utf-8 -*-
"""
模块介绍:

创建者:

创建日期:
"""
import json
import docker
from config.settings import *
import pyrestful.rest
from pyrestful import mediatypes
from pyrestful.rest import get, post, put, delete
from Model.DockerModels import Images, Labels
from sqlalchemy import create_engine, distinct
from sqlalchemy.orm import sessionmaker

from Common.utils import (
    AlchemyJsonEncoder,
    log_hande,
    set_http_head,
    ParamikoClient)
logger = logging.getLogger('docker_cloud_manage_info')

# engine = create_engine("mysql+mysqldb://root:qwer121212@localhost:3306/docker_cloud_manage_local?charset=utf8",encoding="utf-8")
engine = create_engine(
    "mysql+mysqldb://admin:qwer121212.@192.168.43.116:3306/docker_cloud_manage?charset=utf8",
    encoding="utf-8",
    # echo=True
)
SessionCls = sessionmaker(bind=engine)
session = SessionCls()


class ServiceCore(pyrestful.rest.RestHandler):

    @set_http_head
    @get(
        _path="/docker_monarch/docker_node_version",
        _types=[str],
        _produces=mediatypes.APPLICATION_JSON)
    def get_docker_node_version(self):
        """
        docker 节点 版本查询
        protocol + '://' + ipv4 + port == tcp://192.168.43.116:9527

        测试

        GET http://localhost:8080/docker_monarch/docker_node_version?
                                                            protocol=tcp&ipv4=192.168.43.116&port=9527&version=&timeout=

        :return:
            {'Version': '1.12.6',
            'ApiVersion': '1.24',
            'GitCommit': 'ec8512b/1.12.6',
            'GoVersion': 'go1.8.3',
            'Os': 'linux',
            'Arch': 'amd64',
            'KernelVersion': '3.10.0-693.el7.x86_64',
            'BuildTime': '2017-12-11T16:08:42.362786068+00:00',
            'PkgVersion': 'docker-1.12.6-68.gitec8512b.el7.centos.x86_64'
            }
        """
        logger.info()
        protocol = self.get_query_argument('protocol')
        ipv4 = self.get_query_argument('ipv4', 'ipv4')
        port = self.get_query_argument('port')
        version = self.get_query_argument('version', '1.21')
        timeout = self.get_query_argument('timeout', 3)
        client = docker.Client(base_url=protocol+'://'+ipv4+':'+port, version=version, timeout=timeout)
        # 查看版本
        res_dic = {'res_data': client.version()}

        self.write(json.dumps(res_dic))
        return

    @set_http_head
    @post(
        _path="/docker_monarch/docker_node_sync",
        _types=[str],
        _produces=mediatypes.APPLICATION_JSON)
    def sync_docker_node_images(self):
        """

        docker 节点 镜像数据刷新

        若该节点镜像数据有新增则将新增数据加入数据库，反之则不做改动
        protocol + '://' + ipv4 + port == tcp://192.168.43.116:9527

        测试

        GET http://localhost:8080/docker_monarch/docker_node_sync?
                                                            protocol=tcp&ipv4=192.168.43.116&port=9527&version=&timeout=

        :return:
        {
            'Id': 'sha256:960504feb22992c3aa717e5608245212a6361389d177417e8bccfeb04faa8768',
            'ParentId': '',
            'RepoTags': ['eviews:dev'],
            'RepoDigests': None,
            'Created': 1522661619,
            'Size': 595409040,
            'VirtualSize': 595409040,
            'Labels': None
        }
        {
            'Id': 'sha256:f2a91732366c0332ccd7afd2a5c4ff2b9af81f549370f7a19acd460f87686bc7',
            'ParentId': '',
            'RepoTags': None,
            'RepoDigests': [
                'docker.io/hello-world@sha256:27f70fe1ab54eebd2569a33f0b86e5db42b8ebda65d0647d8eceb87d34462efd',
                'docker.io/hello-world@sha256:97ce6fa4b6cdc0790cda65fe7290b74cfebd9fa0c9b8c38e979330d547d22ce1'
            ],
            'Created': 1511223798,
            'Size': 1848,
            'VirtualSize': 1848,
            'Labels': None
        }
        {
            'Id': 'sha256:25980cdf4d63ca7e247f4f2fe9df576c87eb327b281bbfe0cf15249a15a33ddc',
            'ParentId': 'sha256:68f998f26838dd3fb652235cb67cc3729ac8ca6387befbb95b93cd82119e3e1e',
            'RepoTags': ['backend:2.0.0'],
            'RepoDigests': None,
            'Created': 1526609007,
            'Size': 1273249775,
            'VirtualSize': 1273249775,
            'Labels': {}
        }
        {
            'Id': 'sha256:960504feb22992c3aa717e5608245212a6361389d177417e8bccfeb04faa8768',
            'ParentId': '',
            'RepoTags': ['eviews:dev'],
            'RepoDigests': None,
            'Created': 1522661619,
            'Size': 595409040,
            'VirtualSize': 595409040,
            'Labels': None
        }
        """

        protocol = self.get_query_argument('protocol')
        ipv4 = self.get_query_argument('ipv4')
        port = self.get_query_argument('port')
        version = self.get_query_argument('version', default = '1.21')
        timeout = self.get_query_argument('timeout', default = 3)
        client = docker.Client(base_url=protocol+'://'+ipv4+':'+port, version=version, timeout=timeout)

        update_image_id_lis = list()
        # 列出所有镜像
        for image in client.images():
            print(image)
            label_dict = dict()
            image_dict = dict()
            image_id = None
            if image['Labels'] not in [None, {}]:
                label_dict['build_date'] = image['Labels'].get('build-date')
                label_dict['vendor'] = image['Labels'].get('vendor')
                label_dict['name'] = image['Labels'].get('name')
                label_dict['license'] = image['Labels'].get('license')
                label_dict['label_id'] = session.query(Labels.label_id).filter(
                        Labels.build_date == label_dict['build_date'],
                        Labels.vendor == label_dict['vendor'],
                        Labels.name == label_dict['name'],
                        Labels.license == label_dict['license'],
                ).first()
                if label_dict['label_id']:
                    label_id = label_dict['label_id'][0]
                else:
                    images_labels = Labels(**label_dict)
                    session.add(images_labels)
                    session.commit()
                    print('label_id',images_labels.label_id)
                    label_id = images_labels.label_id
            else:
                label_id = None

            image_dict['id'] = image['Id'].split(':')[1]
            image_dict['type'] = image['Id'].split(':')[0]

            # 组装 ParentId
            if image['ParentId'] is not '' and image['ParentId'] is not None and len(image['ParentId']) > 0:
                image_dict['parent_id'] = image['ParentId'].split(':')[1]
                image_dict['parent_type'] = image['ParentId'].split(':')[0]
            else:
                image_dict['parent_id'] = ''
            image_dict['created'] = image['Created']
            if label_id:
                image_dict['labels'] = label_id
            image_dict['ipv4'] = ipv4
            image_dict['virtual_size'] = str(image['VirtualSize'])
            image_dict['size'] = str(image['Size'])
            image_dict['repo_tags'] = image['RepoTags'] not in [None, []] and json.dumps(image['RepoTags']) or ''
            image_dict['repo_digests'] = image['RepoDigests'] not in [None, []] and json.dumps(image['RepoDigests']) or ''

            image_id = session.query(Images.image_id).filter(
                        Images.id == image_dict['id'],
                        # Images.type == image_dict['type'],
                        # Images.virtual_size == image_dict['virtual_size'],
                ).first()

            # 若该节点下该镜像ID已存在 则 更新记录
            if image_id:
                update_image_id_lis.append(image_dict['id'])
                _id = image_dict['id']
                del image_dict['id']
                session.query(Images).filter(Images.id == _id, Images.ipv4 == ipv4 ).update(image_dict)
                session.commit()

            # 若该节点下该镜像ID不存在 则 创建更新记录
            else:
                update_image_id_lis.append(image_dict['id'])
                session.add(Images(**image_dict))
                session.commit()

        # 将该节点下旧DB记录的已失效的镜像记录删除
        update_image_id_tup = tuple(update_image_id_lis)
        session.query(Images).filter(
                Images.ipv4 == ipv4).filter(
                ~Images.id.in_(update_image_id_tup)).delete(synchronize_session=False)
        session.commit()

        res_dic = {'code': 200, 'text': '镜像同步成功'}
        log_content = log_hande(res_dic, 'result_template_02')
        logger.info(log_content)
        self.write(json.dumps(res_dic))

    @set_http_head
    @get(
        _path="/docker_monarch/docker_node_images",
        _types=[str],
        _produces=mediatypes.APPLICATION_JSON)
    def get_docker_node_images(self):
        """
        docker 节点 版本查询
        protocol + '://' + ipv4 + port == tcp://192.168.43.116:9527

        测试

        GET http://localhost:8080/docker_monarch/docker_node_version?
                                                            protocol=tcp&ipv4=192.168.43.116&port=9527&version=&timeout=

        :return:
            [
                {
                    'Id': 'sha256:25980cdf4d63ca7e247f4f2fe9df576c87eb327b281bbfe0cf15249a15a33ddc',
                    'ParentId': 'sha256:68f998f26838dd3fb652235cb67cc3729ac8ca6387befbb95b93cd82119e3e1e',
                    'RepoTags': ['backend:2.0.0'],
                    'RepoDigests': None,
                    'Created': 1526609007,
                    'Size': 1273249775,
                    'VirtualSize': 1273249775,
                    'Labels': {}
                }
                {
                    'Id': 'sha256:960504feb22992c3aa717e5608245212a6361389d177417e8bccfeb04faa8768',
                    'ParentId': '',
                    'RepoTags': ['eviews:dev'],
                    'RepoDigests': None,
                    'Created': 1522661619,
                    'Size': 595409040,
                    'VirtualSize': 595409040,
                    'Labels': None
                }
            ]
        """
        protocol = self.get_query_argument('protocol')
        ipv4 = self.get_query_argument('ipv4')
        port = self.get_query_argument('port')
        version = self.get_query_argument('version') or '1.21'
        timeout = self.get_query_argument('timeout') or 3
        client = docker.Client(base_url=protocol+'://'+ipv4+':'+port, version=version, timeout=timeout)
        # 列出所有镜像
        res_dic = {'res_data': client.images()}
        self.write(json.dumps(res_dic))
        return

    @set_http_head
    @post(
        _path="/docker_monarch/docker_node_image",
        _types=[str],
        _produces=mediatypes.APPLICATION_JSON)
    def pull_docker_node_images(self):
        """
        docker 节点 镜像获取

        由于 同一个节点 有不同 有不同角色的 用户启动容器

        protocol + '://' + ipv4 + port == tcp://192.168.43.116:9527

        测试

        GET http://localhost:8080/docker_monarch/docker_node_version?
                   protocol=tcp&ipv4=192.168.43.116&port=9527&version=&timeout=

        :return:

            若数据库与节点库里不存在该镜像 则拉取该镜像 此处返回拉取状态 此时还需前端 请求 post docker_node_refresh
            若存在 则 该镜像记录就会被返回


            res_data:
            {"status":"Trying to pull repository docker.io/library/hello-world ... "}
            {"status":"Pulling from docker.io/library/hello-world","id":"latest"}
            {"status":"Pulling fs layer","progressDetail":{},"id":"9bb5a5d4561a"}
            {
                "status":"Downloading",
                "progressDetail":{"current":985,"total":985},
                "progress":"==================================================\u003e]    985 B/985 B",
                "id":"9bb5a5d4561a"
            }
            {"status":"Verifying Checksum","progressDetail":{},"id":"9bb5a5d4561a"}
            {"status":"Download complete","progressDetail":{},"id":"9bb5a5d4561a"}
            {
                "status":"Extracting",
                "progressDetail":{"current":985,"total":985},
                "progress":"[==================================================\u003e]    985 B/985 B",
                "id":"9bb5a5d4561a"
            }
            {
                "status":"Extracting",
                "progressDetail":{"current":985,"total":985},
                "progress":"[==================================================\u003e]    985 B/985 B",
                "id":"9bb5a5d4561a"
            }
            {
                "status":"Pull complete",
                "progressDetail":{},
                "id":"9bb5a5d4561a"
            }
            {"status":"Digest: sha256:f5233545e43561214ca4891fd1157e1c3c563316ed8e237750d59bde73361e77"}
            {"status":"Pulling from docker.io/library/hello-world","id":"linux"}
            {"status":"Digest: sha256:c04eb928016c5ba813819c544ed97c24301e8a0a2b5f078a760024a30e861d19"}
            {"status":"Pulling from docker.io/library/hello-world","id":"nanoserver-1709"}
            {
                "errorDetail":{
                    "message":"no supported platform found in manifest list"
                },
                "error":"no supported platform found in manifest list"
            }
        """
        protocol = self.get_query_argument('protocol')
        ipv4 = self.get_query_argument('ipv4')
        port = self.get_query_argument('port')
        version = self.get_query_argument('version') or '1.21'
        timeout = self.get_query_argument('timeout') or 3
        repository = self.get_query_argument('repository') # 镜像源以及标签
        client = docker.Client(base_url=protocol+'://'+ipv4+':'+port, version=version, timeout=timeout)
        #################################################################
        # 此处 判断 镜像 是否 已在数据库里存在 并且 在该节点中确实存在  #
        # 是 则不予拉取 直接返回 数据库里信息                           #
        # 否 则从远程镜像库中 拉取                                      #
        #################################################################
        res_dic = None
        for image in session.query(Images).all():
            if len(image.repo_tags) > 0:
                for each_repo_tag in json.loads(image.repo_tags):
                    if each_repo_tag == repository:
                        # 'res_status': 0,  存在  1 不存在 需要拉取
                        res_dic = {
                            'res_status': 0,
                            'res_data': {
                                'image_id': image.image_id,
                                'id': image.id,
                                'type': image.type,
                                'parent_id': image.parent_id,
                                'parent_type': image.parent_type,
                                'repo_digests': image.repo_digests,
                                'repo_tags': image.repo_tags,
                                'size': image.size,
                                'virtual_size': image.virtual_size,
                                'labels': image.labels
                            }
                        }
                        break
        if res_dic is None:
            status = client.pull(repository)
            res_dic = {'res_status': 1, 'res_data':status}
        self.write(json.dumps(res_dic))
        return







